
class ImCamera {
    constructor() {
        this.stream = null;
        this.currentDeviceId = null;
        // first flip
        this.isFirstFlip = true;
    }

    // get all camera devices
    async getDevices() {
        const devices = await navigator.mediaDevices.enumerateDevices();
        return devices.filter(device => device.kind === 'videoinput');
    }

    // switch camera
    async switchCamera() {
        const devices = await this.getDevices();
        if (devices.length < 2) return; // only one camera

        // switch camera
        let nextDevice;
        if(this.isFirstFlip) {
            const frontCamera = devices.find(device => device.label.includes('front'));
            const backCamera = devices.find(device => device.label.includes('back'));

            // front to back
            if (frontCamera && !this.currentDeviceId) {
                nextDevice = backCamera || devices[0]; // default back
            } else if (backCamera && !this.currentDeviceId) {
                nextDevice = frontCamera || devices[0]; // default front
            } else {
                // if default camera,switch
                nextDevice = devices.find(device => device.deviceId !== this.currentDeviceId);
            }
            this.isFirstFlip = false;
        } else {
            // if next click, by device id to switch
            nextDevice = devices.find(device => device.deviceId !== this.currentDeviceId);
        }

        if (!nextDevice) return;

        // stop current stream
        this.close();

        // update current device id
        this.currentDeviceId = nextDevice.deviceId;

        // get new video stream
        const constraints = {
            video: {
                deviceId: { exact: this.currentDeviceId }
            },
            audio: {
                echoCancellation: true,
                noiseSuppression: true
            }
        };

        try {
            const stream = await navigator.mediaDevices.getUserMedia(constraints);
            this.stream = stream;
            return stream;
        } catch (e) {
            console.log("The camera failed to open properly", e);
            throw new Error("Camera switch failed");
        }
    }
}

ImCamera.prototype.isEnable = function () {
    return !!navigator && !!navigator.mediaDevices && !!navigator.mediaDevices.getUserMedia;
}

// open video stream
ImCamera.prototype.openVideo = function () {
    return new Promise((resolve, reject) => {
        if (this.stream) {
            this.close()
        }
        let constraints = {
            video: true,
            audio: {
                echoCancellation: true, // Audio echo cancellation
                noiseSuppression: true // Turn on noise reduction
            }
        }
        console.log("getUserMedia")
        navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
            console.log("Camera on")
            this.stream = stream;
            resolve(stream);
        }).catch((e) => {
            console.log(e)
            console.log("The camera failed to open properly")
            reject({
                code: 0,
                message: "The camera failed to open properly"
            })
        })
    })
}


ImCamera.prototype.openAudio = function () {
    return new Promise((resolve, reject) => {
        let constraints = {
            video: false,
            audio: {
                echoCancellation: true,
                noiseSuppression: true
            }
        }
        navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
            this.stream = stream;
            resolve(stream);
        }).catch(() => {
            console.log("The microphone does not turn on properly")
            reject({
                code: 0,
                message: "The microphone does not turn on properly"
            })
        })

    })
}

ImCamera.prototype.close = function () {
    // Stop Stream
    if (this.stream) {
        this.stream.getTracks().forEach((track) => {
            track.stop();
        });
    }
}

export default ImCamera;